# encoding: UTF-8

"""
包含一些开放中常用的函数
"""

import configparser
import decimal
import json
import os
import sys
import time
from datetime import datetime, timedelta
import yaml
import numpy as np
import pathlib as pl

sys.path.append(...)

MAX_NUMBER = 10000000000000
MAX_DECIMAL = 4

untrade_day = ['0501']
config_path = os.path.join(pl.Path.home(), '.bq_config')
yml_file_path = os.path.join(config_path, 'data','yml')


def save2yaml_file(data, yml_file):
    """保存数据data到yaml文件yml_file
    :param data:
    :param yml_file: 包含绝对路径的文件名
    """
    with open(yml_file, 'w') as f:
        yaml.dump(data, f)


def dict2kv(source, datetime_format='%Y%m%d %H:%M:%S', include_fields=None):
    """
    将字典转换为：k1,...,kn  v1,...,vn
    :param source: 要转换的dict 源
    :param datetime_format: value 为datetime类型时的格式
    :param include_fields: 过滤key的list or set...
    :return:
    """
    if isinstance(source, dict):
        f = ''
        vl = ''
        if not include_fields:
            for k, v in source.items():
                if isinstance(v, str) and v.strip() and v.strip() != '\0':
                    f = '],['.join([f, k])
                    vl = ",'".join([vl, v.strip()]) + "'"
                elif isinstance(v, float) or isinstance(v, int):
                    f = '],['.join([f, k])
                    vl = ','.join([vl, str(v)])
                elif isinstance(v, datetime):
                    # print('v=', v, type(v))
                    f = '],['.join([f, k])
                    vl = ",'".join([vl, v.strftime(datetime_format)]) + "'"
                else:
                    f = '],['.join([f, k])
                    vl = ",'".join([vl, v.strip()]) + "'"

            f = f[2:]  # delete the first "],"
            f = f + ']'
            vl = vl[1:]  # delete ','
            return f, vl
        else:
            for k, v in source.items():
                if k in include_fields:
                    if isinstance(v, str) and v.strip() and v.strip() != '\0':
                        f = '],['.join([f, k])
                        vl = ",'".join([vl, v]) + "'"
                    elif isinstance(v, float) or isinstance(v, int):
                        f = '],['.join([f, k])
                        vl = ','.join([vl, str(v)])
                    elif isinstance(v, datetime):
                        # print('v=', v, type(v))
                        f = '],['.join([f, k])
                        vl = ",'".join([vl, v.strftime(datetime_format)]) + "'"
                    # elif v:
                    #     f = ','.join([f, k])
                    #     vl = ",'".join([vl, v]) + "'"
            f = f[2:]  # delete the first '
            f = f + "]"
            vl = vl[1:]  # delete ','
            return f, vl
    else:
        return None


def create_class_instance(module_name, class_name, *args, **kwargs):
    """
    create an instance of class_name under module_name with parameters argw, kwargs
    :param module_name: 包含class_name的完整包路径及文件名称
    :param class_name:要创建的类或函数名称，
    :param args:正常参数，要注意顺序
    :param kwargs:缺省参数及可变参数
    :return: the instance of class whose __class_name__ is class_name
    """
    module_meta = __import__(module_name, globals(), locals(), [class_name])
    class_meta = getattr(module_meta, class_name)
    # print('create class instance kwargs:',args,kwargs)
    obj = class_meta(*args, **kwargs)
    return obj


def tostr(value, datetime_format='%Y%m%d %H:%M:%S.%f'):
    # print(value)
    r = value
    if isinstance(value, (int, float)):
        r = str(value)
    if isinstance(value, datetime):
        r = value.strftime(datetime_format)  # time.strftime(datetime_format, value)
    return r


def safe_unicode(value, max_decimal=MAX_DECIMAL):
    """检查接口数据潜在的错误，保证转化为的字符串正确"""
    # 检查是数字接近0时会出现的浮点数上限
    if type(value) is int or type(value) is float:
        if value > MAX_NUMBER:
            value = 0

    # 检查防止小数点位过多
    if isinstance(value, (float, np.float64, )):
        value = round(value, ndigits=max_decimal)

        # d = decimal.Decimal(str(value))
        # if abs(d.as_tuple().exponent) > max_decimal:
        #     value = round(value, ndigits=max_decimal)

    return value


# def loadDBSetting(dbType=DBTYPE_MONGODB):
#     if dbType == DBTYPE_MONGODB:
#         try:
#             with open(os.path.join(config_path, "db_setting.json"))as f:
#                 setting = json.load(f)
#                 mongoSetting = setting['MongoDB']
#         except:
#             host = 'localhost'
#             port = 27017
#             mongoSetting = {"Host": host, "Port": port}
#         return mongoSetting
#     if dbType == DBTYPE_SQLITE:
#         pass


# def loadMongoSetting():
#     """载入MongoDB数据库的配置"""
#     try:
#         with open(os.path.join(config_path, "db_setting.json"))as f:
#             setting = json.load(f)
#             mongoSetting = setting['MongoDB']
#             host = setting['MongoDB']["Host"]
#             port = setting['MongoDB']['Port']
#
#     except:
#         host = 'localhost'
#         port = 27017
#         mongoSetting = {"Host": host, "Port": port}
#
#     return host, port, mongoSetting


def today_date():
    """获取当前本机电脑时间的日期"""
    return datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)


def str_date(day:datetime=None, fmt='%Y%m%d'):
    if day is None:
        return today_date().strftime(fmt)
    else:
        return day.strftime(fmt)


def str_time(tm=None, fmt="%H:%M:%S"):
    if tm:
        return tm.strftime(fmt)
    else:
        return datetime.now().strftime(fmt)


def str_datetime(dttm=None, fmt='%Y%m%d %H:%M:%S'):
    if dttm is None:
        return datetime.now().strftime(fmt)
    elif isinstance(dttm, datetime):
        return dttm.strftime(fmt)
    else:
        return (datetime.now() + timedelta(dttm)).strftime(fmt)


def cur_file_dir():
    # 获取脚本文件的当前路径
    path = sys.path[0]
    # 判断为脚本文件还是py2exe编译后的文件，如果是脚本文件，则返回的是脚本的目录，
    # 如果是py2exe编译后的文件，则返回的是编译后的文件路径
    if os.path.isdir(path):
        return path
    elif os.path.isfile(path):
        return os.path.dirname(path)


def is_trade_time(current_time=time.localtime()):
    """
    判断当前是否是交易时间(可下单）

    """

    if current_time.tm_wday == 6:  # 星期天
        return False

    hour = current_time.tm_hour
    minute = current_time.tm_min
    if current_time.tm_wday == 5 and hour > 2:  # 星期六
        return False
    if current_time.tm_wday == 0 and (hour < 8 or (hour == 8 and minute < 55)):  # 星期一
        return False
    if hour < 2:
        return True
    if hour == 2 and minute < 30:
        return True
    if hour == 8 and 55 <= minute < 59:
        return True
    if hour == 9:
        return True
    if hour == 10 and minute < 15:
        return True
    if hour == 10 and minute > 29:
        return True
    if hour == 11 and minute < 30:
        return True
    if hour == 13 and minute > 29:
        return True
    if hour == 14:
        return True
    if hour >= 21:
        return True

    return False


def save_data2disk_time(currenttime=time.localtime()):
    """保存数据到磁盘的时间"""
    can_login = is_login_time(currenttime)
    hour = currenttime.tm_hour
    minute = currenttime.tm_min
    if can_login:
        if hour == 10 and 14 < minute < 30:
            return True
        if hour == 11 and minute > 29:
            return True
        if hour == 15:
            return True


def get_trading_day(action_day='', action_time=''):
    """根据action day,得出交易日
    :param action_day: yyyymmdd
    :param action_time: hh:mm:ss
    :return 'yyyymmdd'
    """
    if action_day == '':
        current_time = time.localtime()
    else:
        if action_time == '':
            action_time = '00:00:00'
        current_time = time.strptime(action_day + ' ' + action_time, '%Y%m%d %H:%M:%S')
    wd = current_time.tm_wday
    hour = current_time.tm_hour
    # print(current_time)
    today = datetime.strptime(time.strftime('%Y%m%d %H:%M:%S', current_time), '%Y%m%d %H:%M:%S')
    td = today.strftime('%Y%m%d')
    if 6 <= hour <= 18:  # 日盘
        td = today.strftime('%Y%m%d')
    elif hour > 18:  # 12：00前夜盘
        if wd == 4:  # 周五夜盘
            today = today + timedelta(3)
        elif wd < 4:
            today = today + timedelta(1)
        td = today.strftime('%Y%m%d')
    else:  # 00：00后夜盘
        if wd == 5:  # 周六晨盘
            today = today + timedelta(2)
        td = today.strftime('%Y%m%d')

    return td


def is_login_time(currenttime=time.localtime()):
    """
    判断当前是否是交易登录时间
    """
    wd = currenttime.tm_wday
    hour = currenttime.tm_hour
    minute = currenttime.tm_min

    m = currenttime.tm_mon
    d = currenttime.tm_mday
    x = f'{m:02}{d:02}'
    if x in untrade_day:  # 非交易日
        return False

    if wd == 5 and hour >= 3:
        return False
    if wd == 6:  # 星期天
        return False
    if wd == 0 and (hour < 8 or (hour == 8 and minute < 30)):
        return False

    if hour == 8 and minute > 30:
        return True
    if 9 <= hour < 15:
        return True
    if hour == 20 and minute >= 30:
        return True
    if hour >= 21:
        return True
    if hour < 2:
        return True
    if hour == 2 and minute < 30:
        return True
    return False


def getSystemSettings(systemIniFile='system.conf'):
    if systemIniFile == 'system.conf':
        systemIniFile = os.path.join(config_path, systemIniFile)
    systemSettings = {}  # {Section:{Option:value}}
    cf = configparser.ConfigParser()
    cf.read(systemIniFile)

    scts = cf.sections()  # 返回所有的section
    # print("section:", scts)
    for s in scts:
        opts = cf.options(s)  # 返回section s下的所有options
        itms = {}
        for o in opts:
            itm = cf.get(s, o)  # 返回（section s，option o)的值
            itms[o] = itm
        systemSettings[s] = itms
    return systemSettings


def loadSqlitSettings(systemIniFile='system.conf'):
    if systemIniFile == 'system.conf':
        systemIniFile = os.path.join(config_path, systemIniFile)
    sqliteSettings = {}  # {Section:{Option:value}}
    cf = configparser.ConfigParser()
    cf.read(systemIniFile)
    sct = 'Sqlite'

    opts = cf.options(sct)

    for o in opts:
        itm = cf.get(sct, o)  # 返回（section s，option o)的值
        sqliteSettings[o] = itm
    # print(sqliteSettings)
    return sqliteSettings


def debug(msg, isdebug=True):
    if isdebug:
        print(msg)

def get_trade_instruments():
    """"""
    conf_file = 'trade_instruments.yml'
    conf_file = os.path.join(yml_file_path, conf_file)
    conf = {}
    with open(conf_file, encoding='utf8') as f:
        conf = yaml.safe_load(f)

    return conf


def get_ss_instruments(conf_file='ss_cfg.yml'):
    """自选标的"""
    conf_file = os.path.join(yml_file_path, conf_file)
    conf = {}
    with open(conf_file, encoding='utf8') as f:
        conf = yaml.safe_load(f)
    return conf['instruments']


# 自选期货
ss_future = set(get_ss_instruments())


def save_ss_instruments(data, conf_file='ss_cfg.yml'):
    """保存自选标的，data 是一标的代码列表或元组或集合"""
    conf_file = os.path.join(yml_file_path, conf_file)
    instruments = {'instruments': set(data)}
    with open(conf_file, 'w', encoding='utf8') as f:
        yaml.dump(instruments, f)

if __name__ == '__main__':
    days = 10
    ed = str_date()
    sd = str_date(datetime.now() + timedelta(days))
    print(ed, sd, ed > sd)
    print(safe_unicode(1.456789))
    ad = '20181124'
    at = '01:01:00'
    print(get_trading_day(action_day=ad, action_time=at))
    print(get_trading_day())
    print(str_datetime(today_date() - timedelta(30)))
    aa = str_datetime(dttm=-30)

    print((today_date(), aa))
